#!/bin/sh -f
# $Id$
# Copyright (c) 2012 Prabhu Gurumurthy <pgurumur@gmail.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# File vivault generated on Saturday September 22, 2012 @ 10:02:28 PDT
#

# __version__  = "$Revision$"
# __author__   = "$Author$"
# __modified__ = "$Date$"

PROG=`basename $0`
LOCK="/var/tmp/vivault.lock"
CFG_FILE="/opt/local/etc/vivault.conf"
SSLENC="sudo openssl enc -e -aes-256-cbc -in"
ENC_FILE=
MACHINE=`uname -s`
EDIT=0
INIT=0
USER=
INPUT=
OUTPUT=

usage () {
   echo "${PROG} alone opens the encrypted file"
   echo "${PROG} also takes optional arguments"
   echo "${PROG} [ options ]"
   echo "options: "
   echo "  -f [ input clear text file ]"
   echo "  -c [ configuration file to use ]"
   echo "  -e [ edit mode, to modify existing encrypted file ]"
   echo "  -i [ Initial mode to create an encrypted file ]"
   echo "  -h [ prints this help ]"
   exit 1
}

log () {
   mesg=$*
   sudo logger -i ${mesg}
}

rmlock () {
   [ -f ${LOCK} ] && sudo rm -f ${LOCK}
}

cleanup () {
   [ -f ${OUTPUT} ] && sudo rm -f ${OUTPUT}
   [ -f ${INPUT} ] && sudo rm -f ${INPUT}
}

trapset () {
   if [ ${MACHINE} = "OpenBSD" ]; then
      trap "{ sudo rm -f ${LOCK} ${OUTPUT} ${INPUT}; echo $$; exit 255; }" INT TERM
   elif [ ${MACHINE} = "Linux" -o ${MACHINE} = "Darwin" ]; then
      trap "{ sudo rm -f ${LOCK} ${OUTPUT} ${INPUT}; echo $$; exit 255; }" SIGINT SIGTERM
   fi
}

error () {
   mesg=$*

   echo "${PROG}: ${mesg}"
   log ${mesg}
   cleanup;
   rmlock
   exit 1
}

getconfig () {
   if [ -z ${CFG_FILE} -o ! -f ${CFG_FILE} ]; then
      error "configuration file for vivault not found"
   fi

   AUTH_SOURCE=`sudo sed -n 's/auth_source = \(.*\)$/\1/p' ${CFG_FILE}`
   AUTH_SOURCE=`echo ${AUTH_SOURCE} | awk '{ print toupper($0); }'`
   if [ ${AUTH_SOURCE} = "RADIUS" ]; then
      prompt="Enter ${AUTH_SOURCE} username:"
   elif [ ${AUTH_SOURCE} = "GOOGLE" ]; then
      prompt="Enter ${AUTH_SOURCE} username (without domain name):"
   else
      error "unknown authentication method specified"
   fi

   echo -n "${prompt} "
   read USER

   echo -n "Enter ${AUTH_SOURCE} password: "
   stty -echo; read PASS; stty echo; echo;

   status=0
   USERS=`sudo sed -n 's/allowed_users *= *{ *\(.*\) *}/\1/p' ${CFG_FILE}`
   for usr in `echo ${USERS} | sed -e 's/,/ /g'`; do
      usr=`echo ${usr} | awk '{ sub(" ", "", $0); printf("%s", $0); }'`
      if [ ${USER} = ${usr} ]; then
         status=1
         break
      fi
   done

   if [ ${status} -eq 0 ]; then
      error "${USER} not approved to use this progam"
   fi

   STAT=-1
   if [ ${AUTH_SOURCE} = "RADIUS" ]; then
      RADTEST=`which radtest`
      [ -z ${RADTEST} ] && error "radtest binary is undefined"
      [ ! -f ${RADTEST} ] && error "cannot find radtest binary"
      RADSEND="sudo ${RADTEST} ${USER} ${PASS} localhost 1 testing123"
      RADRECV=`${RADSEND} | egrep Access-Accept`
      STAT=$?
   elif [ ${AUTH_SOURCE} = "GOOGLE" ]; then
      SCRIPT=`sudo sed -n 's/auth_script = \(.*\)$/\1/p' ${CFG_FILE}`
      [ -z ${SCRIPT} ] && error "authentication script is not defined!"
      [ ! -f ${SCRIPT} ] && error "cannot find authentication script"
      sudo ${SCRIPT} ${USER} ${PASS}
      STAT=$?
   fi

   if [ ${STAT} -ne 0 ]; then
      error "${USER} authentication failed!"
   else
      ENC_FILE=`sudo sed -n 's/passwd_file = \(.*\)$/\1/p' ${CFG_FILE}`
      if [ ! -f ${ENC_FILE} -o -z ${ENC_FILE} ]; then
         error "password file does not exist or password file not defined"
      fi
   fi
   PASS=
}

getfilepass () {
   echo -n "Enter password for encrypted file: "
   stty -echo; read PASS; stty echo; echo;

   [ -z ${PASS} ] && error "no password supplied"
}

gettmpfile () {
   if [ ${MACHINE} = "OpenBSD" -o ${MACHINE} = "Linux" ]; then
      OUTPUT=`sudo mktemp -p /var/tmp tmp.XXXXXXXXXX`
      INPUT=`sudo mktemp -p /var/tmp tmp.XXXXXXXXXX`
   elif [ ${MACHINE} = "Darwin" ]; then
      OUTPUT=`sudo mktemp /var/tmp/tmp.XXXXXXXXXX`
      INPUT=`sudo mktemp /var/tmp/tmp.XXXXXXXXXX`
   fi

   [ -f ${OUTPUT} -a -f ${INPUT} ] || error "cannot create temporary file"
   [ -f ${OUTPUT} ] && sudo chmod 0600 ${OUTPUT}
}

vivault () {
   edit=$1
   user=`id -unr`
   trapset
   if [ ${edit} -eq 1 ]; then
      if [ -f ${LOCK} ]; then
         sudo awk -F';' '{
            sub(" ", "", $NF);
            printf("%s opened password file on %s, pid: %d\n", $NF, $1, $2);
            printf("vivault: password file busy, try again later\n");
         }' ${LOCK}
         exit 1
      fi

      pid=$$
      touch ${LOCK}
      echo "`date`; ${pid}; ${user}" >> ${LOCK}
      sudo chmod 0444 ${LOCK}
      sudo chown root:wheel ${LOCK}

      [ ! -f ${LOCK} ] && error "cannot create lockfile, bailing out..."
      [ -z ${LOCK} ] && error "${LOCK} file is empty!"
   fi

   getconfig
   gettmpfile
   getfilepass
   EDITOR=`env | awk -F'=' '$1 == "EDITOR" { print $NF; }'`
   [ -z ${EDITOR}  ] && EDITOR=vi

   SSLDEC="sudo openssl enc -d -aes-256-cbc -in"
   if [ -f ${ENC_FILE} ]; then
      ${SSLDEC} ${ENC_FILE} -out ${OUTPUT} -pass pass:${PASS} >/dev/null 2>&1
      if [ $? -eq 0 ]; then
         editor=
         if [ ${edit} -eq 1 ]; then
            [ -f ${LOCK} ] || error "lock file not created... exiting..."
            [ -f ${LOCK} ] && log "${USER} opened password for editing"
            if [ -f ${LOCK} -a -f ${OUTPUT} ]; then
               [ ${EDITOR} = "vi" -o ${EDITOR} = "vim" ] && editor=vi
               [ ${EDITOR} = "vis" -o ${EDITOR} = "elvis" ] && editor=vi
               [ ${EDITOR} = "nvi" ] && editor=vi
            fi
         else
            log "${USER} opened password for editing"
            if [ -f ${OUTPUT} ]; then
               [ ${EDITOR} = "vi" -o ${EDITOR} = "vim" ] && editor=view
               [ ${EDITOR} = "vis" -o ${EDITOR} = "elvis" ] && editor=view
               [ ${EDITOR} = "nvi" ] && editor=view
            fi
         fi

         sudo ${editor} ${OUTPUT}
         clear
      else
         error "error in decrypting, can you check your password?"
      fi

      if [ ${edit} -eq 1 ]; then
         ${SSLENC} ${OUTPUT} -out ${INPUT} -pass pass:${PASS} >/dev/null 2>&1
         err=1
         if [ $? -eq 0 ]; then
            [ -z ${INPUT} ] && error "input file is empty, something went wrong"
            sudo mv ${INPUT} ${ENC_FILE}
            sudo chmod 0664 ${ENC_FILE}
            sudo chown root:wheel ${ENC_FILE}
            log "changed password file saved"
            err=0
         fi

         cleanup; rmlock
         [ ${err} -ne 0 ] && exit 1
      fi

      cleanup; rmlock
   else
      error "password file does not exist"
   fi
}

if [ $# -lt 1 ]; then
   vivault 0
else
   while getopts f:c:ieh arg; do
      case ${arg} in
         f)
            INPUT=${OPTARG}
            ;;

         c)
            CFG_FILE=${OPTARG}
            ;;

         i)
            INIT=1
            ;;

         e)
            EDIT=1
            ;;

         h)
            usage
            ;;

         *)
            usage
            ;;
      esac
   done

   if [ ${EDIT} -eq 1 ]; then
      vivault 1
   elif [ ${INIT} -eq 1 ]; then
      [ ! -f ${CFG_FILE} ] && error "Cannot proceed without config file"
      ENC_FILE=`sudo sed -n 's/passwd_file = \(.*\)$/\1/p' ${CFG_FILE}`
      [ -z ${INPUT} ] && gettmpfile
      NEW="/tmp/vaultedconf"
      sudo mv ${INPUT} ${NEW}
      sudo ${EDITOR} ${NEW}
      if [ ! -z ${NEW} ]; then
         getfilepass
         ${SSLENC} ${NEW} -out ${ENC_FILE} -pass pass:${PASS} > /dev/null 2>&1
         if [ $? -ne 0 ]; then
            sudo rm -f ${NEW}
            error "Cannot initialize/encrypt password file"
         fi
      else
         sudo rm -f ${NEW}
         error "temporary file ${NEW} is empty"
      fi
      cleanup
   else
      usage
   fi
fi
